#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <fitsio.h>

#define ROWS 9400
#define COLS 10000
#define CHANNELS_PER_ROW 16
#define PIXELS_PER_CHANNEL 1250
#define DATA_PER_READ 20000  // 16 * 1250

void rearrange_data(uint16_t *binarray, uint16_t *uin, uint16_t *lin) {
    // 重排前10000个数据到uin
    for (int i = 0; i < PIXELS_PER_CHANNEL; i++) {
        // 通道a,b,c,d: 正序 (a1a2...a1250, b1b2...b1250, c1c2...c1250, d1d2...d1250)
        uin[i] = binarray[i * CHANNELS_PER_ROW + 0];  // a
        uin[i + PIXELS_PER_CHANNEL] = binarray[i * CHANNELS_PER_ROW + 1];  // b
        uin[i + 2 * PIXELS_PER_CHANNEL] = binarray[i * CHANNELS_PER_ROW + 2];  // c
        uin[i + 3 * PIXELS_PER_CHANNEL] = binarray[i * CHANNELS_PER_ROW + 3];  // d
        
        // 通道e,f,g,h: 反序 (e1250e1249...e1, f1250f1249...f1, g1250g1249...g1, h1250h1249...h1)
        uin[4 * PIXELS_PER_CHANNEL + i] = binarray[(PIXELS_PER_CHANNEL - 1 - i) * CHANNELS_PER_ROW + 4];  // e
        uin[5 * PIXELS_PER_CHANNEL + i] = binarray[(PIXELS_PER_CHANNEL - 1 - i) * CHANNELS_PER_ROW + 5];  // f
        uin[6 * PIXELS_PER_CHANNEL + i] = binarray[(PIXELS_PER_CHANNEL - 1 - i) * CHANNELS_PER_ROW + 6];  // g
        uin[7 * PIXELS_PER_CHANNEL + i] = binarray[(PIXELS_PER_CHANNEL - 1 - i) * CHANNELS_PER_ROW + 7];  // h
    }
    
    // 重排后10000个数据到lin
    for (int i = 0; i < PIXELS_PER_CHANNEL; i++) {
        // 通道p,o,n,m: 正序 (p1p2...p1250, o1o2...o1250, n1n2...n1250, m1m2...m1250)
        lin[i] = binarray[i * CHANNELS_PER_ROW + 15];  // p
        lin[i + PIXELS_PER_CHANNEL] = binarray[i * CHANNELS_PER_ROW + 14];  // o
        lin[i + 2 * PIXELS_PER_CHANNEL] = binarray[i * CHANNELS_PER_ROW + 13];  // n
        lin[i + 3 * PIXELS_PER_CHANNEL] = binarray[i * CHANNELS_PER_ROW + 12];  // m
        
        // 通道l,k,j,i: 反序 (l1250l1249...l1, k1250k1249...k1, j1250j1249...j1, i1250i1249...i1)
        lin[4 * PIXELS_PER_CHANNEL + i] = binarray[(PIXELS_PER_CHANNEL - 1 - i) * CHANNELS_PER_ROW + 11];  // l
        lin[5 * PIXELS_PER_CHANNEL + i] = binarray[(PIXELS_PER_CHANNEL - 1 - i) * CHANNELS_PER_ROW + 10];  // k
        lin[6 * PIXELS_PER_CHANNEL + i] = binarray[(PIXELS_PER_CHANNEL - 1 - i) * CHANNELS_PER_ROW + 9];   // j
        lin[7 * PIXELS_PER_CHANNEL + i] = binarray[(PIXELS_PER_CHANNEL - 1 - i) * CHANNELS_PER_ROW + 8];   // i
    }
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Usage: %s <bin_file> <fits_file>\n", argv[0]);
        return 1;
    }
    
    char *bin_file = argv[1];
    char *fits_file = argv[2];
    
    // printf("Reading binary file: %s\n", bin_file);
    // printf("Output FITS file: %s\n", fits_file);
    
    // 打开bin文件
    FILE *fp_bin = fopen(bin_file, "rb");
    if (!fp_bin) {
        printf("Error: Cannot open binary file %s\n", bin_file);
        return 1;
    }
    
    // 分配内存：一次性读入所有数据
    uint16_t *all_data = (uint16_t *)malloc(ROWS * COLS * sizeof(uint16_t));
    if (!all_data) {
        printf("Error: Memory allocation failed\n");
        fclose(fp_bin);
        return 1;
    }
    
    // 读取所有数据
    size_t read_size = fread(all_data, sizeof(uint16_t), ROWS * COLS, fp_bin);
    if (read_size != ROWS * COLS) {
        printf("Error: Expected %ld uint16 values, but read %ld\n", 
               (long)(ROWS * COLS), (long)read_size);
        free(all_data);
        fclose(fp_bin);
        return 1;
    }
    fclose(fp_bin);
    printf("Successfully read %ld uint16 values\n", (long)read_size);
    
    // 创建FITS文件
    fitsfile *fptr;
    int status = 0;
    long naxes[2] = {COLS, ROWS};
    
    // 记录开始时间
    struct timeval start_time, end_time;
    gettimeofday(&start_time, NULL);
    printf("Starting FITS file creation and data writing...\n");
    
    fits_create_file(&fptr, fits_file, &status);
    if (status) {
        printf("Error: Cannot create FITS file\n");
        free(all_data);
        return 1;
    }
    
    fits_create_img(fptr, USHORT_IMG, 2, naxes, &status);
    if (status) {
        printf("Error: Cannot create FITS image\n");
        fits_close_file(fptr, &status);
        free(all_data);
        return 1;
    }
    
    // 分配临时数组用于重排数据
    uint16_t *uarray = (uint16_t *)malloc(COLS * sizeof(uint16_t));
    uint16_t *larray = (uint16_t *)malloc(COLS * sizeof(uint16_t));
    
    // printf("Processing data row by row...\n");
    
    // 每次处理20000个数据（16个通道的一行），重排后写入FITS的两行
    for (int row = 0; row < ROWS / 2; row++) {
        // 计算当前20000个数据的起始位置
        // all_data + row * DATA_PER_READ 指向第row组20000个数据的开始
        uint16_t *current_data = all_data + row * DATA_PER_READ;
        
        // 重排数据：将20000个数据重排成两个10000数组
        // uarray: 前10000个数据（通道a,b,c,d正序 + 通道e,f,g,h反序）
        // larray: 后10000个数据（通道p,o,n,m正序 + 通道l,k,j,i反序）
        rearrange_data(current_data, uarray, larray);
        
        // 写入FITS文件
        // fpixel[2]: 指定写入数据的起始像素位置 [列, 行]
        // FITS使用1-based索引（从1开始计数）
        long fpixel[2];
        
        // 写入第一行（从上到下）
        // fpixel[0] = 1: 从第1列开始写入
        // fpixel[1] = row + 1: 从第(row+1)行开始写入
        // 例如：row=0时写入第1行，row=1时写入第2行，...
        fpixel[0] = 1;
        fpixel[1] = row + 1;
        fits_write_pix(fptr, TUSHORT, fpixel, COLS, uarray, &status);
        
        // 写入第二行（从下到上）
        // fpixel[1] = ROWS - row: 从倒数第(row+1)行开始写入
        // 例如：row=0时写入第9400行，row=1时写入第9399行，...
        fpixel[1] = ROWS - row;
        fits_write_pix(fptr, TUSHORT, fpixel, COLS, larray, &status);
        
        if (status) {
            printf("Error: Failed to write FITS data at row %d\n", row);
            break;
        }
        
        // 显示进度
        // if ((row + 1) % 100 == 0) {
        //     printf("Processed %d/%d rows\n", row + 1, ROWS / 2);
        // }
    }
    
    // 记录结束时间并计算总时间
    gettimeofday(&end_time, NULL);
    double total_time = (end_time.tv_sec - start_time.tv_sec) + 
                       (end_time.tv_usec - start_time.tv_usec) / 1000000.0;
    
    // 清理资源
    fits_close_file(fptr, &status);
    free(uarray);
    free(larray);
    free(all_data);
    
    if (status) {
        printf("Error: FITS file operation failed\n");
        return 1;
    }
    
    printf("Successfully created FITS file: %s\n", fits_file);
    printf("Total time for FITS creation and data writing: %.3f seconds\n", total_time);
    return 0;
} 